// import { reactive } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { ComponentTypeEnum, FormState } from '../types/index';
import {
  DATA_SOURCE_TYPE_TYPE,
  DATA_API_SOURCE_TYPE,
  MULTIPLE_SELECT,
  DISABLED_TYPE,
} from '../consts';
import { FormSchema, FormActionType } from '/@/components/Form/index';
import dayjs from 'dayjs';
import { isEmpty, isNullOrUnDef } from '/@/utils/is';
import { mergeFunctions } from '/@/utils';
// import { useDebounceFn } from '@vueuse/core';
import { useMessage } from '/@/hooks/web/useMessage';
import { getRealApi } from './functionSet';

import {
  getOptionsForSelectApi,
  getOptionsForTreeSelectApi,
  comFileUploadApi,
  delFileApi,
} from '/@/api/config-center/model-design';

import { downloadByData } from '/@/utils/file/download';

// const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
function setPickerProps(propsParams: Indexable) {
  const { component, style } = propsParams;
  if (!component || !component.includes('Picker')) return propsParams;
  if (!style) {
    propsParams.style = 'width:100%';
  }
  return propsParams;
}

function setSelectProps(
  propsParams: Indexable,
  {
    modelId,
    preview,
    formState,
  }: {
    modelId: string;
    preview?: boolean;
    formState: Indexable;
  },
) {
  const { field, componentType, dataSourceType, resourceCode } = propsParams;

  if (![ComponentTypeEnum.ApiSelect, ComponentTypeEnum.ApiTreeSelect].includes(componentType))
    return propsParams;

  if (componentType === ComponentTypeEnum.ApiSelect) {
    if (propsParams.selectType >= MULTIPLE_SELECT) {
      propsParams.mode = 'multiple';
    }
  }

  if (componentType === ComponentTypeEnum.ApiTreeSelect) {
    propsParams.multiple = propsParams.selectType >= MULTIPLE_SELECT;
  }

  if (![DATA_SOURCE_TYPE_TYPE].includes(dataSourceType)) {
    let apiFn = async (params) => {
      if (dataSourceType === DATA_API_SOURCE_TYPE) return;
      return await getOptionsForSelectApi({
        ...params,
        modelId,
        field,
        params: {
          ...formState.params,
          ...params,
        },
      });
    };

    // 下拉接口配置预览不需要配接口
    if (componentType === ComponentTypeEnum.ApiTreeSelect && !preview) {
      apiFn = async (params) => {
        // todo 参数优化
        return await getOptionsForTreeSelectApi({
          ...params,
          modelId: modelId,
          field,
          params: {
            ...formState.params,
            ...params,
          },
        });
      };
    }

    if (dataSourceType === DATA_API_SOURCE_TYPE) {
      apiFn = async (params) => {
        return await getRealApi({
          params: {
            ...formState.params,
            ...params,
            field,
            modelId,
          },
          apiCode: resourceCode,
        });
      };
    }

    propsParams.api = apiFn;
    propsParams.filterOption = false;
    propsParams.showSearch = true;

    propsParams.isModelForm = true;
  }

  return propsParams;
}

function setUploadProps(propsParams, { modelId }) {
  const { field, maxSize, maxNumber, accept, componentType, parentParams } = propsParams;
  if (componentType !== ComponentTypeEnum.Upload) return propsParams;

  propsParams.api = comFileUploadApi;
  propsParams.delApi = delFileApi;

  propsParams.uploadParams = { parentParams: JSON.stringify(parentParams), field, modelId };

  propsParams.maxSize = maxSize ?? 5;
  propsParams.multiple = maxNumber > 1;
  propsParams.maxNumber = maxNumber ?? Infinity;
  const acceptStr = accept ?? '';
  propsParams.accept = acceptStr ? acceptStr.split(',') : [];

  return propsParams;
}
function setRadioProps(propsParams) {
  const { componentType } = propsParams;
  if (componentType !== ComponentTypeEnum.RadioGroup) return propsParams;
  propsParams.class = '!ml-1';
  return propsParams;
}

function setTextAreaProps(propsParams: Indexable) {
  const { componentType, minRows, maxRows } = propsParams;
  if (componentType !== ComponentTypeEnum.InputTextArea) return propsParams;

  if (minRows || maxRows) {
    propsParams.autoSize = { minRows, maxRows };
  }
  return propsParams;
}

function setReadonlyProps(propsParams) {
  const { component } = propsParams;
  if (component !== 'Upload') return propsParams;
  propsParams.type = 'Upload';
  return propsParams;
}

function setDeptSelectProps(propsParams: Indexable) {
  if (propsParams.componentType === ComponentTypeEnum.HChooseUser) {
    propsParams.type = 0;
    return propsParams;
  }
  if (propsParams.componentType !== ComponentTypeEnum.HChooseDept) return propsParams;
  propsParams.type = 3;

  return propsParams;
}

function setSubTableProps(propsParams: Indexable) {
  const { componentType, simpleChildTable, updateType } = propsParams;
  if (componentType !== ComponentTypeEnum.SubTable) return propsParams;
  propsParams.disabled = updateType === DISABLED_TYPE;
  propsParams.config = simpleChildTable;

  return propsParams;
}

function setNumberProps(propsParams: Indexable) {
  const { componentType, delimiter } = propsParams;

  if (componentType !== ComponentTypeEnum.InputNumber) return propsParams;

  if (!isNullOrUnDef(delimiter) && delimiter !== '') {
    propsParams.formatter = (v) => {
      return `${v}`.replace(/\B(?=(\d{3})+(?!\d))/g, delimiter);
    };
    const reg = new RegExp(`\$\s?|(${delimiter}*)`, 'g');

    propsParams.parser = (v) => {
      return `${v}`.replace(reg, '');
    };
  }
  return propsParams;
}

export default function setCustomProps(
  propsParams: Indexable,
  formState: Partial<FormState>,
  callbackMap: {
    formActionType?: Partial<FormActionType>; //当前表单方法
    parentFormActionType?: Partial<FormActionType>; // 父级表单方法
  } = {},
) {
  const { modelId = '', preview } = formState;
  let props = {};

  propsParams.callbackMap = callbackMap;
  propsParams.formState = formState;

  props = setPickerProps(propsParams);

  props = setDeptSelectProps(propsParams);

  props = setSubTableProps(propsParams);

  props = setReadonlyProps(propsParams);

  props = setTextAreaProps(propsParams);

  props = setRadioProps(propsParams);

  props = setSelectProps(propsParams, {
    formState,
    preview,
    modelId,
  });

  props = setUploadProps(propsParams, {
    modelId,
  });

  props = setNumberProps(propsParams);

  return props;
}

export function setCustomEvent(
  schema: FormSchema,
  formState: Indexable = {},
  callbackMap: {
    getRecord?: Fn;
    formActionType?: FormActionType; //当前表单方法
    parentFormActionType?: Partial<FormActionType>; // 父级表单方法
  },
) {
  const currentComponentProps = schema.componentProps as Indexable;

  const { event } = currentComponentProps;

  if (event && !isEmpty(event)) {
    const objEvnt: any = {};
    Object.keys(event).forEach((eventName) => {
      const item = event[eventName] as any;
      if (item.funcList && item.funcList.length) {
        const funcList = item.funcList.map(({ scriptText }) => {
          return new Function(
            'context',
            'args',
            'defHttp',
            `return (async function(context,args,defHttp) {
              ${scriptText};
          })
          (context,args,defHttp)`,
          );
        });

        //  如果存在事件将事件提取出来放到第一个执行
        const firstFn = currentComponentProps[eventName];

        if (firstFn) {
          funcList.push(firstFn);
        }

        const allFn = mergeFunctions(...funcList);

        //  有自定义函数 则合并生成函数
        objEvnt[eventName] = allFn;
      }
    });
    const messageFn = useMessage();
    const context = {
      schema,
      callbackMap,
      dayjs,
      messageFn,
      formActionType: callbackMap.formActionType,
      parentParams: formState.params,
      userInfo: formState.userInfo,
      downloadByData,
    };

    schema.componentProps = Object.assign({}, currentComponentProps, createFn(objEvnt, context));
  }
  return schema;
}

function createFn(objEvnt: Indexable, context) {
  const fns: any = {};
  Object.entries(objEvnt).forEach(([name, fn]: [string, Fn]) => {
    fns[name] = (...args) => {
      const params: any = [];
      args.forEach((el) => {
        const p = el && el.target ? el.target.value : el;

        params.push(p);
      });

      const getRecord = context.callbackMap.getRecord;
      context.formModel = getRecord ? getRecord() : context.formActionType?.getFieldsValue();

      if (context.formActionType?.findSchema) {
        context.schema = context.formActionType.findSchema();
      }

      fn(context, params, defHttp);
    };
  });
  return fns;
}
